import re

from kubernetes import client

from dashboard.k8s import K8sApi, dt_format


# 详情页相关api

class PodListForNode(K8sApi):
    def __init__(self, request):
        super().__init__(request)
        self.api = client.CoreV1Api()
        self.node_name = request.GET.get('node_name')

    def get(self):
        data = []
        for pod in self.api.list_pod_for_all_namespaces().items:
            node_name = pod.spec.node_name
            # 不属于此节点的pod则跳过
            if node_name != self.node_name:
                continue

            pod_name = pod.metadata.name
            namespace = pod.metadata.namespace
            status = ("运行中" if pod.status.conditions[-1].status else "异常")
            host_network = pod.spec.host_network
            pod_ip = ("主机网络" if host_network else pod.status.pod_ip)
            create_time = dt_format(pod.metadata.creation_timestamp)
            try:
                cpu_limit = pod.spec.containers[0].resources.limits['cpu']
            except Exception as e:
                cpu_limit = 0
            try:
                memory_limit = pod.spec.containers[0].resources.limits['memory']
            except Exception as e:
                memory_limit = 0
            try:
                memory_requests = pod.spec.containers[0].resources.requests['memory']
            except Exception as e:
                memory_requests = 0
            try:
                cpu_requests = pod.spec.containers[0].resources.requests['cpu']
            except Exception as e:
                cpu_requests = 0
            data.append({'pod_name': pod_name, 'namespace': namespace, 'status': status, 'pod_ip': pod_ip,
                         'create_time': create_time, 'cpu_limit': cpu_limit, 'memory_limit': memory_limit,
                         'memory_requests': memory_requests,
                         'cpu_requests': cpu_requests})
        count = len(data)
        data = self.paging(data)
        code = 0
        msg = '获取数据成功'
        res = {'code': code, 'msg': msg, 'count': count, 'data': data}
        return res


class NodeDetailsInfo(K8sApi):
    def __init__(self, request):
        super().__init__(request)
        self.api = client.CoreV1Api()
        self.node_name = request.GET.get('node_name')

    # 内存单位转GB
    def memory_unit_to_g(self, memory):
        if memory.endswith("M") or memory.endswith("Mi"):
            m = re.findall("\d+", memory)[0]
            g = round(float(m) / 1024, 2)
            return g
        elif memory.endswith("K") or memory.endswith("Ki"):
            k = re.findall("\d+", memory)[0]
            g = round(float(k) / 1024 / 1024, 2)
            return g
        elif memory.endswith("G") or memory.endswith("Gi"):
            g = re.findall("\d+", memory)[0]
            return float(g)
        else:
            k = re.findall("\d+", memory)[0]
            g = round(float(k) / 1024 / 1024 / 1024, 2)
            return g

    # CPU单位转浮点数
    def cpu_unit_to_f(self, cpu):
        if cpu.endswith("m"):
            n = re.findall("\d+", cpu)[0]
            n = round(float(n) / 1000, 2)
            return n
        else:
            return float(cpu)

    def node_resources(self):
        node_resources = {}
        for node in self.api.list_node().items:
            node_name = node.metadata.name
            if node_name != self.node_name:
                continue
            # 可分配容量
            allocatable_cpu = node.status.allocatable['cpu']
            allocatable_memory = node.status.allocatable['memory']
            allocatable_ephemeral_storage = node.status.allocatable['ephemeral-storage']
            # 总容量
            capacity_cpu = node.status.capacity['cpu']
            capacity_memory = node.status.capacity['memory']
            capacity_ephemeral_storage = node.status.capacity['ephemeral-storage']
            capacity_pods = node.status.capacity['pods']
            # 状态
            schedulable = node.spec.unschedulable
            status = node.status.conditions[-1].status

            contents = {'allocatable_cpu': self.cpu_unit_to_f(allocatable_cpu),
                        'allocatable_memory': self.memory_unit_to_g(allocatable_memory),
                        'allocatable_ephemeral_storage': self.memory_unit_to_g(allocatable_ephemeral_storage),
                        'capacity_cpu': self.cpu_unit_to_f(capacity_cpu),
                        'capacity_memory': self.memory_unit_to_g(capacity_memory),
                        'capacity_ephemeral_storage': self.memory_unit_to_g(capacity_ephemeral_storage),
                        'capacity_pods': capacity_pods, 'schedulable': schedulable, 'status': status,
                        'cpu_requests': 0, 'memory_requests': 0, 'memory_limits': 0, 'cpu_limits': 0, 'pods_number': 0}
            node_resources[node_name] = contents

        for pod in self.api.list_pod_for_all_namespaces().items:
            node_name = pod.spec.node_name
            if node_name is None or node_name != self.node_name:
                continue
            pod_name = pod.metadata.name
            # 遍历pod中容器
            for c in pod.spec.containers:
                c_name = c.name
                # 资源请求
                if c.resources.requests is not None:
                    if "cpu" in c.resources.requests:
                        cpu_request = c.resources.requests["cpu"]
                        # 之前用 += 方式，但浮点数运算时会出现很多位小数，所以要用round取小数
                        node_resources[node_name]['cpu_requests'] = round(
                            node_resources[node_name]['cpu_requests'] + self.cpu_unit_to_f(cpu_request), 2)
                    if "memory" in c.resources.requests:
                        memory_request = c.resources.requests["memory"]
                        node_resources[node_name]['memory_requests'] = round(
                            node_resources[node_name]['memory_requests'] + self.memory_unit_to_g(memory_request), 2)
                # 资源限制
                if c.resources.limits is not None:
                    if "cpu" in c.resources.limits:
                        cpu_limit = c.resources.limits["cpu"]
                        node_resources[node_name]['cpu_limits'] = round(
                            node_resources[node_name]['cpu_limits'] + self.cpu_unit_to_f(cpu_limit), 2)
                    if "memory" in c.resources.limits:
                        memory_limit = c.resources.limits["memory"]
                        node_resources[node_name]['memory_limits'] = round(
                            node_resources[node_name]['memory_limits'] + self.memory_unit_to_g(memory_limit), 2)
            # 添加Pod数量
            node_resources[node_name]['pods_number'] += 1
        return node_resources[self.node_name]

    def node_info(self):
        node_info = {}
        for node in self.api.list_node().items:
            node_name = node.metadata.name
            if node_name != self.node_name:
                continue
            node_info[node_name] = {"node_name": "", "hostname": "", "internal_ip": "", "os": "", "cpu_arch": "",
                                    "kernel": "", "pod_cidr": "",
                                    "container_runtime_version": "", "kubelet_version": "", "kube_proxy_version": "",
                                    "labels": "", "unschedulable": "", "taints": "", "create_time": ""}
            node_info[node_name]["node_name"] = node_name
            for i in node.status.addresses:
                if i.type == "InternalIP":
                    node_info[node_name]["internal_ip"] = i.address
                elif i.type == "Hostname":
                    node_info[node_name]["hostname"] = i.address
            node_info[node_name]["pod_cidr"] = node.spec.pod_cidr
            node_info[node_name]["os"] = node.status.node_info.os_image
            node_info[node_name]["kernel"] = node.status.node_info.kernel_version
            node_info[node_name]["cpu_arch"] = node.status.node_info.architecture
            node_info[node_name]["container_runtime_version"] = node.status.node_info.container_runtime_version
            node_info[node_name]["kubelet_version"] = node.status.node_info.kubelet_version
            node_info[node_name]["kube_proxy_version"] = node.status.node_info.kube_proxy_version
            node_info[node_name]["unschedulable"] = ("是" if node.spec.unschedulable else "否")
            node_info[node_name]["labels"] = node.metadata.labels
            node_info[node_name]["taints"] = node.spec.taints
            node_info[node_name]["create_time"] = dt_format(node.metadata.creation_timestamp)

        return node_info[self.node_name]


class DeploymentDetailsInfo(K8sApi):
    def __init__(self, request):
        super().__init__(request)
        self.api = client.AppsV1Api()
        self.core_api = client.CoreV1Api()
        self.network_api = client.NetworkingV1Api()

    def history_info(self):
        name = self.request.GET.get('name')
        namespace = self.request.GET.get('namespace')
        data = []

        for rs in self.api.list_namespaced_replica_set(namespace=namespace).items:
            current_dp_name = rs.metadata.owner_references[0].name
            rs_name = rs.metadata.name
            if name == current_dp_name:
                namespace = rs.metadata.namespace
                replicas = rs.status.replicas
                # available_replicas = rs.status.available_replicas
                # ready_replicas = rs.status.ready_replicas
                revision = rs.metadata.annotations["deployment.kubernetes.io/revision"]
                create_time = dt_format(rs.metadata.creation_timestamp)

                containers = {}
                for c in rs.spec.template.spec.containers:
                    containers[c.name] = c.image

                rs = {"name": rs_name, "namespace": namespace, "replicas": replicas,
                      "revision": revision, 'containers': containers, "create_time": create_time}
                # print(rs)
                data.append(rs)
        count = len(data)  # 可选，rs默认保存10条，所以不用分页
        res = {"code": 0, "msg": "", "count": count, 'data': data}
        return res

    def deployment_info(self):
        name = self.request.GET.get('name')
        namespace = self.request.GET.get('namespace')
        for deployment in self.api.list_namespaced_deployment(namespace=namespace).items:
            dp_name = deployment.metadata.name
            if dp_name == name:
                replicas = deployment.spec.replicas
                available_replicas = deployment.status.available_replicas
                images = []
                for container in deployment.spec.template.spec.containers:
                    images.append(container.image)
                labels = deployment.metadata.labels
                create_time = dt_format(deployment.metadata.creation_timestamp)
                rolling_update = deployment.spec.strategy.rolling_update
                volumes = deployment.spec.template.spec.volumes
                tolerations = deployment.spec.template.spec.tolerations
                containers = deployment.spec.template.spec.containers
                dp_info = {'name': dp_name, 'namespace': namespace, 'replicas': replicas,
                           'available_replicas': available_replicas, 'images': images, 'labels': labels,
                           'create_time': create_time, 'rolling_update': rolling_update, 'volumes': volumes,
                           'tolerations': tolerations, 'containers': containers}
                # 根据标签查看service是否配置
                services = []
                ingress = {}
                for service in self.core_api.list_namespaced_service(namespace=namespace).items:
                    if dp_info['labels'] == service.spec.selector:
                        # services.append(eval(str(service.spec)))
                        svc_name = service.metadata.name
                        type = service.spec.type
                        cluster_ip = service.spec.cluster_ip
                        ports = service.spec.ports
                        data = {'type': type, 'cluster_ip': cluster_ip, 'ports': ports}
                        services.append(data)

                        # 根据service查看ingress是否配置
                        for i in self.network_api.list_namespaced_ingress(namespace=namespace).items:
                            for rule in i.spec.rules:
                                for k in rule.http.paths:
                                    if k.backend.service.name == svc_name:
                                        rules = i.spec.rules
                                        tls = i.spec.tls
                                        ingress['rules'] = rules
                                        ingress['tls'] = tls

                dp_info['service'] = services
                dp_info['ingress'] = ingress
                # print(ingress)
        return dp_info
